#include <iostream>
#include "herm/base/utils/misc.h"
#include "herm/base/utils/log.h"
#include "herm/base/utils/timer_heap.h"
#include "herm/base/container/buffer.h"
#include "herm/base/socket/socket_def.h"
#include "tcp_session.h"
#include "accept_handler.h"
#include "ts_peer.h"

TSPeer::TSPeer() : m_peerParam(true, false)
{
	m_tmpBuf = nullptr;
	m_tcpSessionObjMgr = nullptr;
	m_socks = nullptr;
	m_timerHeap = nullptr;
}

TSPeer::~TSPeer()
{
	HERM_DELETE(m_tcpSessionObjMgr);
	HERM_DELETE_ARRAY(m_socks);
	HERM_DELETE_ARRAY(m_tmpBuf);
	HERM_DELETE_ARRAY(m_timerHeap);
}

void TSPeer::Reset(const herm::Address& addr, herm::Multiplexor* multiplexor, 
	herm::IListener* listener,  herm::IMsgHandler* handler, int connTimeout, const herm::TCPeerParam& peerParam) 
{
	m_listener = listener;
    m_handler = handler;
	m_peerParam = peerParam;
	delete[] m_tmpBuf;
	m_tmpBuf = new char[m_peerParam.recvTCPBufSize];

	delete m_tcpSessionObjMgr;
    int sessionCount = peerParam.sessionCount;
#ifdef WIN32
    if (sessionCount > 64)
        sessionCount = 64;
#endif
	m_tcpSessionObjMgr = new TCPSessionObjMgr(sessionCount);
	for (int i = 0; i < sessionCount; i++)
	{
		TCPSession* session = m_tcpSessionObjMgr->GetObj(i);
		session->Init(multiplexor, this, i, &m_peerParam, m_tmpBuf); 
	}

	delete m_socks;
	m_socks = new herm::Handle[peerParam.acceptTCPQueueSize];

	delete m_timerHeap;
	m_timerHeap = nullptr;
	m_connTimeout = connTimeout;
	if (connTimeout > 0)
		m_timerHeap = new herm::TimerHeap(peerParam.sessionCount);

	AcceptHandler::Reset(addr, multiplexor, peerParam.acceptTCPQueueSize);

    std::cout << "Create TCP Server Peer: \n";
    std::cout << "TCP Session Count: " << peerParam.sessionCount << " On Windows count:" << sessionCount << std::endl;
    std::cout << "Accept Queue Size: " << peerParam.acceptTCPQueueSize << std::endl;
    HERM_INFO("Create TCP Server Peer:");
    HERM_INFO("TCP Session Count:%d;  But On Windows count:%d", peerParam.sessionCount, sessionCount);
    HERM_INFO("Accept Queue Size:%d", peerParam.acceptTCPQueueSize);
    HERM_INFO("Receive Buffer Size:%d", m_peerParam.recvTCPBufSize);
}

int TSPeer::AcceptSessions(bool& busy, herm::int64_t curTick)
{
	busy = false;
	if (!herm::IsValidState(m_state))
		return m_state;

	int bytes = m_acceptSocks->Fetch(reinterpret_cast<char*>(m_socks), m_peerParam.acceptTCPQueueSize);
	if (bytes == 0)
		return m_state;

	int count = bytes / sizeof(herm::Handle);
	for (int i = 0; i < count; i++)
	{
		TCPSession* session = AcquireSessionObj<TCPSession>(m_tcpSessionObjMgr);
		if (session)
		{
			session->Reset(m_socks[i], false, m_timerHeap, curTick, m_connTimeout * 1000);
			m_listener->Accept(session);
		}
		else
		{
			m_listener->PeerError(herm::ST_SESSION_COUNT_IS_MAX, herm::Private::GetLastError());
			herm::Private::Close(m_socks[i]);
		}
	}

	busy = true;
	return m_state;
}

herm::ISession* TSPeer::CreateSession(const std::string& servName, 
	const herm::Address& remoteAddr, bool isReconnect, bool isBlock, 
	herm::INBCNotifier* notifier)
{
	(void)servName;
	(void)remoteAddr;
	(void)notifier;
	(void)isBlock;
	return nullptr;
}

herm::ISession* TSPeer::GetSession(int idx)
{
	return m_tcpSessionObjMgr->GetObj(idx);
}

void TSPeer::DestroySession(int sessinIdx)
{
	TCPSession* tcpSession = m_tcpSessionObjMgr->GetObj(sessinIdx);
	if (tcpSession)
	{
		tcpSession->Finish();
		m_tcpSessionObjMgr->Release(sessinIdx);
		HERM_INFO("Release session(idx=%d)", sessinIdx);
	}
}
 
void TSPeer::Finish()
{
	Close();
}

herm::IListener* TSPeer::GetListener() const
{
	return m_listener;
}

void TSPeer::Tick(herm::int64_t curTick)
{
	if (m_timerHeap)
		m_timerHeap->Run(curTick);
}

